package com.ruibang.glass.quality.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ruibang.glass.common.constants.CommonErrorCode;
import com.ruibang.glass.quality.constant.Constants;
import com.ruibang.glass.quality.constant.QualityErrorCode;
import com.ruibang.glass.quality.domain.req.DefectDetailReq;
import com.ruibang.glass.quality.domain.req.DefectRuleDetailReq;
import com.ruibang.glass.quality.domain.req.DefectRuleReq;
import com.ruibang.glass.quality.domain.resp.DefectDetailResp;
import com.ruibang.glass.quality.domain.resp.GlassHqInfo;
import com.ruibang.glass.quality.mapper.ShelfLotItemMapper;
import com.ruibang.glass.quality.service.DefectDetailService;
import com.ruibang.glass.quality.service.GlassStationService;
import com.ruibang.glass.quality.service.TotalEquDataService;
import com.ruibang.glass.quality.util.PoiUtils;
import com.teaming.cloud.framework2.common.exception.ServiceException;
import com.teaming.cloud.framework2.common.model.ResultBody;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Author: songJinKang
 * @CreateTime: 2024-01-12  13:49
 * @Description: TODO
 * @Version: 1.0
 */

@Slf4j
@Service
public class DefectDetailServiceImpl implements DefectDetailService {

    @Autowired
    private GlassStationService glassStationService;

    @Autowired
    private ShelfLotItemMapper shelfLotItemMapper;

    @Autowired
    private TotalEquDataService totalEquDataService;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public ResultBody<Map<String, List<DefectDetailResp>>> getDefectDetail(DefectDetailReq defectDetailReq) {
        if (defectDetailReq == null) {
            return ResultBody.fail(QualityErrorCode.PARAM_ERROR.getCode(), QualityErrorCode.PARAM_ERROR.getMsg());
        }
        switch (defectDetailReq.getQueryDimension()) {
            //检查时间
            case Constants.ONE_STR: {
                List<DefectDetailResp> defectDetailResps = processJcDimension(defectDetailReq);
                Map<String, List<DefectDetailResp>> defectDetailMap = defectDetailResps.stream().collect(Collectors.groupingBy(DefectDetailResp::getDefectName));
                return ResultBody.success(defectDetailMap);
            }
            //横切时间维度
            case Constants.TWO_STR: {
                List<DefectDetailResp> defectDetailResps = processHqDimension(defectDetailReq);
                Map<String, List<DefectDetailResp>> defectDetailMap = defectDetailResps.stream().collect(Collectors.groupingBy(DefectDetailResp::getDefectName));
                return ResultBody.success(defectDetailMap);
            }
            default: {
                return ResultBody.fail(QualityErrorCode.UNKNOWN_DIMENSION_TYPE.getCode(), QualityErrorCode.UNKNOWN_DIMENSION_TYPE.getMsg());
            }
        }
    }


    @Override
    public void export(@RequestBody DefectDetailReq defectDetailReq, HttpServletResponse response) {
        defectDetailReq.setIsQuery(Constants.ZERO_STR);
        ResultBody<Map<String, List<DefectDetailResp>>> resultBody = this.getDefectDetail(defectDetailReq);
        Map<String, List<DefectDetailResp>> defectDetailMap = resultBody.getData();

        if (defectDetailMap != null && defectDetailMap.size() > 0) {
            List<DefectDetailResp> data = new ArrayList<>();
            Collection<List<DefectDetailResp>> values = defectDetailMap.values();
            for (List<DefectDetailResp> defectDetails : values) {
                data.addAll(defectDetails);
            }
            //创建工作簿
            Workbook workbook = new SXSSFWorkbook(-1);
            Sheet abSheet = workbook.createSheet("数据");

            //set样式
            PoiUtils.setGlobalStyle(workbook);

            //set数据
            AtomicInteger sumRowCount = new AtomicInteger(0);
            //设置表头
            Row headRow = abSheet.createRow(sumRowCount.get());
            for (int i = 0; i < Constants.DEFECT_DETAIL_TABLE_HEADERS.length; i++) {
                Cell cell = headRow.createCell(i);
                cell.setCellValue(Constants.DEFECT_DETAIL_TABLE_HEADERS[i]);
            }
            sumRowCount.addAndGet(Constants.ONE_INT);
            //set表格数据
            for (DefectDetailResp defectDetailRsp : data) {
                Row row = abSheet.createRow(sumRowCount.get());
                for (int i = 0; i < Constants.DEFECT_DETAIL_TABLE_HEADERS.length; i++) {
                    Cell headRowCell = row.createCell(i);
                    if (i == 0) {
                        headRowCell.setCellValue(defectDetailRsp.getGlassId());
                        abSheet.setColumnWidth(i, 17 * 256);
                    }
                    if (i == 1) {
                        headRowCell.setCellValue(defectDetailRsp.getDefectName());
                        abSheet.setColumnWidth(i, 17 * 256);
                    }
                    if (i == 2) {
                        LocalDateTime startTime = defectDetailRsp.getStartTime();
                        if (startTime != null) {
                            headRowCell.setCellValue(startTime.format(com.ruibang.glass.common.constants.Constants.DATE_TIME_FORMATTER));
                        } else {
                            headRowCell.setCellValue("");
                        }
                        abSheet.setColumnWidth(i, 20 * 256);
                    }
                    if (i == 3) {
                        LocalDateTime stationStartTime = defectDetailRsp.getStationStartTime();
                        if (stationStartTime != null) {
                            headRowCell.setCellValue(stationStartTime.format(com.ruibang.glass.common.constants.Constants.DATE_TIME_FORMATTER));
                        } else {
                            headRowCell.setCellValue("");
                        }
                        abSheet.setColumnWidth(i, 20 * 256);

                    }
                    if (i == 4) {
                        headRowCell.setCellValue(defectDetailRsp.getTiltedSize());
                        abSheet.setColumnWidth(i, 17 * 256);
                    }
                    if (i == 5) {
                        headRowCell.setCellValue(defectDetailRsp.getTiltedDiv());
                        abSheet.setColumnWidth(i, 17 * 256);
                    }
                    if (i == 6) {
                        headRowCell.setCellValue(defectDetailRsp.getX());
                        abSheet.setColumnWidth(i, 17 * 256);
                    }
                    if (i == 7) {
                        headRowCell.setCellValue(defectDetailRsp.getY());
                        abSheet.setColumnWidth(i, 17 * 256);
                    }
                }
                sumRowCount.getAndAdd(Constants.ONE_INT);
            }
            //返回excel
            try {
                response.setContentType("application/vnd.ms-excel");
                response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("PointData.xlsx", "utf-8"));
                ServletOutputStream outputStream = response.getOutputStream();
                workbook.write(outputStream);
            } catch (IOException e) {
                throw new ServiceException(CommonErrorCode.MONITOR_DATA_EXPORT_FAIL.getCode(), CommonErrorCode.MONITOR_DATA_EXPORT_FAIL.getMsg());
            }
        }
    }

    /**
     * @Description: 横切时间维度
     * @version v1.0
     * @author songJinKang
     * @date 2024-01-12 16:17
     */
    private List<DefectDetailResp> processHqDimension(DefectDetailReq defectDetailReq) {
        //获取热端玻璃ID
        long start;
        long end;
        start = defectDetailReq.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        end = defectDetailReq.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        List<GlassHqInfo> hqDetailByDate = shelfLotItemMapper.getHqDetailByDate(String.valueOf(start), String.valueOf(end));
        if (CollectionUtils.isNotEmpty(hqDetailByDate)) {
            List<String> hotGlassId = hqDetailByDate.stream().map(GlassHqInfo::getGlassId).collect(Collectors.toList());
            //根据热端玻璃ID获取冷端玻璃ID
            List<String> coldGlassIds = glassStationService.getColdGlassId(hotGlassId);
            List<String> customerPanelId = coldGlassIds.stream().map(e -> e.substring(6)).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(customerPanelId)) {
                //根据冷端玻璃ID获取对应横切时间
                AtomicReference<Map<String, LocalDateTime>> hqDetailMap = new AtomicReference<>();
                CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
                    hqDetailMap.set(glassStationService.getColdGlassIdMappingStationStartTime(hqDetailByDate, coldGlassIds));
                }, threadPoolTaskExecutor);
                //拼接SQL
                StringBuilder sql = new StringBuilder();
                sql.append("SELECT CustomerPanelId AS glassId,DefectName AS defectName,StartTime AS StartTime,MaterialCenterDW AS x,MaterialCenterCW AS y,TiltedSize AS tiltedSize,TiltedDiv AS tiltedDiv FROM total_equ_data where ");
                sql.append("is_finished = ").append(Constants.ONE_STR);
                sql.append(" AND MachineId ='Inspect' ");
                if (CollectionUtils.isNotEmpty(coldGlassIds)) {
                    //拼接规则
                    List<DefectRuleDetailReq> defectRuleDetails = defectDetailReq.getDefectRuleDetail();
                    if (CollectionUtils.isNotEmpty(defectRuleDetails)) {
                        AtomicInteger i = new AtomicInteger();
                        for (DefectRuleDetailReq defectRuleDetail : defectRuleDetails) {
                            if (StringUtils.isNotBlank(defectRuleDetail.getDefectName())) {
                                //缺陷名称
                                if (i.get() > 0) {
                                    sql.append("OR (DefectName = '").append(defectRuleDetail.getDefectName()).append("'");
                                } else {
                                    sql.append("AND (");
                                    sql.append("(DefectName = '").append(defectRuleDetail.getDefectName()).append("'");
                                }

                                //规则
                                List<DefectRuleReq> defectRules = defectRuleDetail.getDefectRules();
                                if (CollectionUtils.isNotEmpty(defectRules)) {

                                    AtomicInteger ruleCount = new AtomicInteger();
                                    if ((defectRules.get(0).getMaxSize() != null && defectRules.get(0).getMinSize() != null)
                                            || (defectRules.get(0).getMaxLevel() != null && defectRules.get(0).getMinLevel() != null)) {
                                        sql.append(" AND (");
                                    }

                                    for (DefectRuleReq defectRule : defectRules) {
                                        int switchCount = 0;
                                        if (defectRule.getMaxSize() != null && defectRule.getMinSize() != null) {
                                            sql.append("(TiltedSize >= ").append(defectRule.getMinSize() / 1000);
                                            sql.append(" AND TiltedSize <= ").append(defectRule.getMaxSize() / 1000);
                                            switchCount++;
                                        }
                                        if (defectRule.getMaxLevel() != null && defectRule.getMinLevel() != null) {
                                            if (switchCount > 0) {
                                                sql.append("AND TiltedDiv >= ").append(defectRule.getMinLevel());
                                                sql.append(" AND TiltedDiv <= ").append(defectRule.getMaxLevel());
                                            } else {
                                                sql.append("(TiltedDiv >= ").append(defectRule.getMinLevel());
                                                sql.append(" AND TiltedDiv <= ").append(defectRule.getMaxLevel());
                                            }
                                        }

                                        if ((defectRule.getMaxSize() != null && defectRule.getMinSize() != null)
                                                || (defectRule.getMaxLevel() != null && defectRule.getMinLevel() != null)) {
                                            if (ruleCount.get() == defectRules.size() - 1) {
                                                sql.append(")");
                                            } else {
                                                sql.append(") or ");
                                            }
                                        }

                                        ruleCount.getAndIncrement();
                                    }
                                    if ((defectRules.get(0).getMaxSize() != null && defectRules.get(0).getMinSize() != null)
                                            || defectRules.get(0).getMaxLevel() != null && defectRules.get(0).getMinLevel() != null) {
                                        sql.append(")");
                                    }
                                }
                                sql.append(")");
                            }
                            i.getAndIncrement();
                        }
                        sql.append(")");
                    }

                    //拼接玻璃ID
                    sql.append("and CustomerPanelId in (");
                    for (int i = 0; i < customerPanelId.size(); i++) {
                        sql.append("'");
                        sql.append(customerPanelId.get(i));
                        if (i == customerPanelId.size() - 1) {
                            sql.append("'");
                        } else {
                            sql.append("',");
                        }
                    }
                    sql.append(")");
                }

                //限制XY大小
                sql.append(" AND (MaterialCenterDW <= 2800 and MaterialCenterDW >= 0) AND (MaterialCenterCW <= 2500 and MaterialCenterCW >= 0)");

                //执行sql
                log.error("执行sql：{}", sql.toString());
                List<DefectDetailResp> defectDetailResp = totalEquDataService.queryDefectDetailData(sql.toString());
                if (CollectionUtils.isNotEmpty(defectDetailResp)) {
                    //设置横切时间
                    completableFuture.join();
                    if (hqDetailMap.get() != null && hqDetailMap.get().size() > 0) {
                        for (DefectDetailResp detailResp : defectDetailResp) {
                            LocalDateTime stationStartTime = hqDetailMap.get().get(detailResp.getGlassId());
                            detailResp.setStationStartTime(stationStartTime);
                        }
                    }
                    return defectDetailResp;
                }
            }
        }
        return Collections.emptyList();
    }


    /**
     * @Description: 检查时间维度
     * @version v1.0
     * @author songJinKang
     * @date 2024-01-12 16:17
     */
    private List<DefectDetailResp> processJcDimension(DefectDetailReq defectDetailReq) {
        //获取热端玻璃ID
        String start = defectDetailReq.getStartTime().format(com.ruibang.glass.common.constants.Constants.DATE_TIME_FORMATTER);
        String end = defectDetailReq.getEndTime().format(com.ruibang.glass.common.constants.Constants.DATE_TIME_FORMATTER);

        //拼接SQL
        StringBuilder sql = new StringBuilder();
        if (Constants.ONE_STR.equals(defectDetailReq.getIsQuery())) {
            sql.append("SELECT DefectName AS defectName,MaterialCenterDW AS x,MaterialCenterCW AS y FROM total_equ_data where ");
        } else {
            sql.append("SELECT CustomerPanelId AS glassId,DefectName AS defectName,StartTime AS StartTime,MaterialCenterDW AS x,MaterialCenterCW AS y,TiltedSize AS tiltedSize,TiltedDiv AS tiltedDiv FROM total_equ_data where ");
        }
        sql.append("is_finished = ").append(Constants.ONE_STR);
        sql.append(" AND MachineId ='Inspect' ");
        if (StringUtils.isNotBlank(defectDetailReq.getIsDirectInvestment())) {
            sql.append("AND (CustomerBatchId LIKE '66%' ");
            String[] split = defectDetailReq.getIsDirectInvestment().split("_");
            if (split.length == 1) {
                sql.append("OR CustomerBatchId LIKE '").append(split[0]).append("%')");
            } else {
                sql.append("OR ");
                for (int i = 0; i < split.length; i++) {
                    if (i == split.length - 1) {
                        sql.append("CustomerBatchId LIKE '").append(split[i]).append("%')");
                    } else {
                        sql.append("CustomerBatchId LIKE '").append(split[i]).append("%' OR ");
                    }
                }
            }
        }

        //拼接规则
        List<DefectRuleDetailReq> defectRuleDetails = defectDetailReq.getDefectRuleDetail();
        if (CollectionUtils.isNotEmpty(defectRuleDetails)) {
            AtomicInteger i = new AtomicInteger();
            for (DefectRuleDetailReq defectRuleDetail : defectRuleDetails) {
                if (StringUtils.isNotBlank(defectRuleDetail.getDefectName())) {
                    //缺陷名称
                    if (i.get() > 0) {
                        sql.append("OR (DefectName = '").append(defectRuleDetail.getDefectName()).append("'");
                    } else {
                        sql.append("AND (");
                        sql.append("(DefectName = '").append(defectRuleDetail.getDefectName()).append("'");
                    }

                    //规则
                    List<DefectRuleReq> defectRules = defectRuleDetail.getDefectRules();
                    if (CollectionUtils.isNotEmpty(defectRules)) {

                        AtomicInteger ruleCount = new AtomicInteger();
                        if ((defectRules.get(0).getMaxSize() != null && defectRules.get(0).getMinSize() != null)
                                || (defectRules.get(0).getMaxLevel() != null && defectRules.get(0).getMinLevel() != null)) {
                            sql.append(" AND (");
                        }

                        for (DefectRuleReq defectRule : defectRules) {
                            int switchCount = 0;
                            if (defectRule.getMaxSize() != null && defectRule.getMinSize() != null) {
                                sql.append("(TiltedSize >= ").append(defectRule.getMinSize() / 1000);
                                sql.append(" AND TiltedSize <= ").append(defectRule.getMaxSize() / 1000);
                                switchCount++;
                            }
                            if (defectRule.getMaxLevel() != null && defectRule.getMinLevel() != null) {
                                if (switchCount > 0) {
                                    sql.append("AND TiltedDiv >= ").append(defectRule.getMinLevel());
                                    sql.append(" AND TiltedDiv <= ").append(defectRule.getMaxLevel());
                                } else {
                                    sql.append("(TiltedDiv >= ").append(defectRule.getMinLevel());
                                    sql.append(" AND TiltedDiv <= ").append(defectRule.getMaxLevel());
                                }
                            }

                            if ((defectRule.getMaxSize() != null && defectRule.getMinSize() != null)
                                    || (defectRule.getMaxLevel() != null && defectRule.getMinLevel() != null)) {
                                if (ruleCount.get() == defectRules.size() - 1) {
                                    sql.append(")");
                                } else {
                                    sql.append(") or ");
                                }
                            }

                            ruleCount.getAndIncrement();
                        }
                        if ((defectRules.get(0).getMaxSize() != null && defectRules.get(0).getMinSize() != null)
                                || defectRules.get(0).getMaxLevel() != null && defectRules.get(0).getMinLevel() != null) {
                            sql.append(")");
                        }
                    }
                    sql.append(")");
                }
                i.getAndIncrement();
            }
            sql.append(")");
        }

        //时间
        sql.append(" AND StartTime between ").append("'").append(start).append("'").append(" AND ").append("'").append(end).append("'");


        //限制XY大小
        sql.append(" AND (MaterialCenterDW <= 2800 and MaterialCenterDW >= 0) AND (MaterialCenterCW <= 2500 and MaterialCenterCW >= 0)");


        //执行sql
        log.error("执行sql：{}", sql.toString());
        List<DefectDetailResp> defectDetailResp = totalEquDataService.queryDefectDetailData(sql.toString());


        if (Constants.ZERO_STR.equals(defectDetailReq.getIsQuery()) && CollectionUtils.isNotEmpty(defectDetailResp)) {
            //冷端玻璃ID
            List<String> coldGlassId = defectDetailResp.stream().map(e -> Constants.COLD_GLASS_ID_PREFIX.concat(e.getGlassId())).collect(Collectors.toList());

            //根据冷端玻璃ID查询热端玻璃ID
            Map<String, LocalDateTime> coldGlassIdMappingStationStartTime = glassStationService.getColdGlassIdMappingStationStartTime(coldGlassId);

            //设置横切时间
            for (DefectDetailResp detailResp : defectDetailResp) {
                String customerPanelId = detailResp.getGlassId();
                LocalDateTime stationStartTime = coldGlassIdMappingStationStartTime.get(customerPanelId);
                if (stationStartTime != null) {
                    detailResp.setStationStartTime(stationStartTime);
                }
            }
        }
        return defectDetailResp;
    }


}
